<?php

define( "TEMPLATE_TAGS_DIR", dirname( __FILE__ ) . "/Tags" );


require_once "TemplateDOMDocument.class.php";
require_once "TemplateTag.class.php";


// Exceptions
require_once "Exceptions/TemplateTagNotFound.class.php";
require_once "Exceptions/TemplateTagInvalid.class.php";
require_once "Exceptions/TemplateTagIdNotFound.class.php";


class Template
{
	public static $TEMPLATE_DIR = ".";
	public static $CACHE_DIR = ".";
	public static $CACHE_EXPIRE = 0;


	private $DOM;

	private $templateFile;
	private $cachedFile;

	private $cached = FALSE;
	
	private $elements = array();


	public function __construct( $file, $hash = NULL )
	{
		// File: User/user_add.tpl
		// Hash: administrator

		// TemplateFile: ../Templates/User/user_add.tpl
		$this->templateFile = Template::$TEMPLATE_DIR . "/" . $file;

        // CachedFile: ../Cache/User/user_add__administrator__d39k2328...
		$this->cachedFile = Template::$CACHE_DIR . "/"
		. str_replace( ".", "-", substr( $file, 0, strrpos( $file, "." ) ) )
		. ( ( $hash !== NULL ) ? "__" . $hash . "__" : "" )
		. md5( $this->templateFile );

		// Check if cache exists
		if ( Template::$CACHE_EXPIRE > 0 && file_exists( $this->cachedFile ) ) {
			// Check for possible expire time
			if ( ( filemtime( $this->cachedFile ) + Template::$CACHE_EXPIRE ) > time() ) {
				$this->cached = TRUE;
			}
		}

		if ( ! $this->cached ) {
			// Check if file exists
			if ( file_exists( $this->templateFile ) ) {
				$this->DOM = TemplateDOMDocument::getDocument();
				$this->DOM->preserveWhiteSpace = TRUE;
				$this->DOM->load( $this->templateFile );
			}
		}
	}
	
	
	public function isCached()
	{
		return $this->cached;
	}
	
	
	public function getTemplateFile()
	{
		return $this->templateFile;
	}
	
	
	public function getCachedFile()
	{
		if ( $this->cached ) {
			return $this->cachedFile;
		}

		return "";
	}
	

	public function setEncoding( $encoding )
	{
		$this->DOM->encoding = $encoding;
	}
	
	
	public function getElement( $elementId )
	{
		if ( isset( $this->elements[ $elementId ] ) ) {
			return $this->elements[ $elementId ];
		} else {
			$DOMElement = $this->DOM->getElementById( $elementId );
	
			if ( $DOMElement !== NULL ) {
				$tagName = $DOMElement->tagName;
				$tag = explode( ":", $tagName );
				$tag = ucfirst( $tag[0] . ucfirst( $tag[1] ) );
				
				// Check if class is defined
				if ( ! class_exists( $tag ) ) {
					require_once TEMPLATE_TAGS_DIR . "/" . $tag . ".tag.php";
				} else {
					throw new TemplateTagNotFound(
						"Cannot handle tag [ " . $tagName . " ]. Tag handler not found."
					);
				}

				// Assure we are dealing with a true tag
				if ( is_subclass_of( $tag, "TemplateTag" ) ) {
					$this->elements[ $elementId ] = new $tag( $elementId, $DOMElement, $this->DOM );
					
					return $this->elements[ $elementId ];
				} else {
					throw new TemplateTagInvalid(
						"Tag [ " . $tagName . " ] cannot be manipulated by a non tag handler class."
					);
				}
			}
		}

		throw new TemplateTagIdNotFound(
			"Element [ " . $elementId . " ] does not exist in file [ " . $this->templateFile . " ]"
		);
	}

	
	public function render()
	{
		if ( $this->cached ) {
        	print file_get_contents( $this->cachedFile );
		} else {
			$this->process();

			$this->DOM->saveHTMLFile("php://output");
			
			if ( Template::$CACHE_EXPIRE > 0 ) {
				$this->generateCache();
			}
		}
	}


	public function output( $encoding = "utf-8" )
	{
    	if ( $this->cached ) {
			return file_get_contents( $this->cachedFile );
		} else {
			$this->process();

			return $this->DOM->saveHTML();
		}
	}


	private function generateCache()
	{
    	$bytes = $this->DOM->saveHTMLFile( $this->cachedFile );

		if ( $bytes !==  FALSE ) {
			$this->cached = TRUE;
		}
	}
	
	
	private function process()
	{
		foreach ( $this->elements as $element ) {
			$element->render();
		}

		// Remove itens from elements srray to prevent recompilations
		$this->elements = array();
		
		// We can still have some itens that were not dealt in the application
		$elements = $this->DOM->getElementsByTagNameNS( "http://www.bisna.com/BISNA", "*" );

		foreach ( $elements as $element ) {
		}

	}
}

?>